// 10.4 再探迭代器
/**
 * 除了为每个容器定义的迭代器之外，标准库在头文件iterator中还定义了额外几种迭代器。
 * 1. 插入迭代器：被绑定到一个容器上，用来向容器插入元素。
 * 2. 流迭代器：被绑定到输入或输出流上，用来遍历所关联的IO流。
 * 3. 反向迭代器：向后而不是向前移动，除了forward_list之外的标准库容器都有反向迭代器。
 * 4. 移动迭代器：这些专用的迭代器不拷贝其中的元素，而是移动它们。
 */

#include <iterator>
#include <vector>
#include <list>
#include <deque>
#include <forward_list>
#include <string>
#include <array>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
#include <functional>
#include <iostream>
using std::swap;
using std::vector, std::list, std::deque, std::forward_list, std::string, std::array, std::stack, std::queue;
#include "../Chapter07/Sales_data.h"
#include "../Chapter01/Sales_item.h"
using std::begin, std::cbegin, std::end, std::cend, std::find, std::accumulate, std::equal, std::fill, std::fill_n, std::back_inserter;
using std::cin, std::cout, std::endl;
using std::copy, std::replace, std::replace_copy, std::sort, std::unique, std::stable_sort, std::find_if, std::for_each;
using std::ostream, std::ref;
using std::transform, std::bind, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3;
using namespace std;

int main()
{
    // 10.4.3 反向迭代器
    // 反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。对于反向迭代器，递增（以及递减）操作的含义会颠倒过来。
    // 我们可以通过调用rbegin、rend、crbegin和crend成员函数来获得反向迭代器。这些成员函数返回指向容器尾元素和首元素之前一个位置的迭代器。
    // 下面的循环是一个使用反向迭代器的例子，它按逆序打印vec中的元素：[插图]
    vector<int> vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (auto r_iter = vec.crbegin(); // 将r_iter绑定到尾元素
         r_iter != vec.crend();       // crend指向首元素之前的位置
         ++r_iter)                    // 实际是递减，移动到前一个元素
    {
        cout << *r_iter << endl;
    }

    // 反向迭代器需要递减运算符

    // 反向迭代器和其他迭代器之间的关系
    // 先看个例子：
    string line("FIRST,MIDDLE,LAST");
    auto comma = find(line.cbegin(), line.cend(), ','); // 在一个逗号分隔的列表中查找第一个元素
    cout << string(line.cbegin(), comma) << endl;
    auto rcomma = find(line.crbegin(), line.crend(), ','); // 使用反向迭代器查找最后一个元素
    cout << string(line.crbegin(), rcomma) << endl;        // 错误：将逆向输出单词的字符，会输出TSAL而不是LAST
    // 我们通过调用reverse_iterator的base成员函数来完成这一转换，此成员函数会返回其对应的普通迭代器：[插图]
    cout << string(rcomma.base(), line.cend()) << endl; // 正确：得到一个正向迭代器，输出LAST

    // 从技术上讲，普通迭代器与反向迭代器的关系反映了左闭合区间（参见9.2.1节，第296页）的特性。
    // 关键点在于[line.crbegin（），rcomma）和[rcomma.base（），line.cend（））指向line中相同的元素范围。
    // 为了实现这一点，rcomma和rcomma.base（）必须生成相邻位置而不是相同位置，crbegin（）和cend（）也是如此。

    // 反向迭代器的目的是表示元素范围，而这些范围是不对称的，这导致一个重要的结果：
    // 当我们从一个普通迭代器初始化一个反向迭代器，或是给一个反向迭代器赋值时，结果迭代器与原迭代器指向的并不是相同的元素。

    return 0;
}
